/**
 * CS 340 Fatboy Mafia Team
 */
package fatboy.hypeerweb;

import org.junit.Assert;
import org.junit.Test;

/**
 * Black Box Testing:
 * 
 * First test cases has the following equivalence classes:
 * 	- an instance of EdgeNodeState
 *  - an instance of SurfaceNodeState
 *  - an instance of InteriorNodeState
 *  - an instance of LastNodeState
 *  - an instance of NullNodeState
 *  If all the functionality of the properly instantiated node state works in one instance,
 *  	it is going to work on other instances.
 * 
 * White box testing of the child-classed of NodeState abstract class.
 *  
 * Second test case is Complete condition testing for hypeer webs containing 1 to 5 nodes.
 * All tests together implement data-flow testing and integration testing.
 * 
 * 1) Data-flow testing.
 * There is a single way to create an instance of a NodeState subclass - through the
 *  default constructor. Therefore, the first test case test that single data-flow
 *  possibility.
 *  
 * See test case for branch coverage of hasParent method in the TestSurfaceNodeState.java
 * It tests both branches of hasParent on an artificially created stand alone surface node.
 * 
 * 2) Internal Boundary Value Testing.
 * Since the node states can only be EdgeNodeState, SurfaceNodeState, InteriorNodeState,
 * 	LastNodeState, and NullNodeState (defined by NodeType enumeration), it's impossible
 * 	to set the node to the invalid state or go past the boundary of the valid states.
 * 	  
 * 3) Relational Condition Testing.
 * NodeStates implement the State Pattern, which eliminated the necessity of the switch
 *  and if statements. All the method of all of the subclasses of NodeState are linear
 *  and don't contain any conditionals. Therefore, no Relational Condition Testing is
 *  possible.
 *  
 * 4) Loop Testing.
 * There are no loops in the NodeState class or any of its subclasses. Therefore, no
 * 	loop testing is possible.
 * 
 * @author Ilya Vinogradov
 */
public class TestNodeState {

	/**
	 * Tests artificially created states on a stand alone node
	 * (Equivalence partitions testing)
	 */
	@Test
	public void testArtificialStates() {
		NodeState edge = new EdgeNodeState();
		NodeState surf = new SurfaceNodeState();
		NodeState inter = new InteriorNodeState();
		NodeState last = new LastNodeState();
		NodeState nulls = new NullNodeState(); 
		
		Node test = new Node("stuff", new NodeAddress(99));
		Assert.assertEquals(99, test.hashCode());
		last.assertNodeStateIsCorrect(test);
		Assert.assertEquals(last.findInsertionPoint(test) , test);
		Assert.assertNull(last.getFirstUpDownNodeAddress(test));
		Assert.assertFalse(last.hasEdgeChild(test));
		
		test.setNodeState(NodeType.EDGE_NODE);
		Assert.assertFalse(edge.hasEdgeChild(test));
		//Assert.assertTrue(edge.hasParent(test)); //built-in assumption
		
		test.setNodeState(NodeType.INTERIOR_NODE);
		Assert.assertFalse(inter.hasEdgeChild(test));
		Assert.assertFalse(inter.hasParent(test));
		
		test.setNodeState(NodeType.SURFACE_NODE);
		Assert.assertFalse(surf.hasEdgeChild(test));
		Assert.assertFalse(surf.hasParent(test));
		
		test.setNodeState(NodeType.NULL_NODE);
		//testing built-in assumptions
		Assert.assertFalse(nulls.hasEdgeChild(test));
		Assert.assertFalse(nulls.hasParent(test));
		Assert.assertNull(nulls.findInsertionPoint(test));
		Assert.assertNull(nulls.getFirstUpDownNodeAddress(test));
		Assert.assertNull(nulls.getSurfaceOrLastNode(test));
	}
	
	/**
	 * Tests the changes of the state of a particular node
	 * 	as hypeer web grows
	 * 
	 * (Complete condition testing for hypeer webs containing 1 to 5 nodes)
	 */
	@Test
	public void testStateChanges() {
		//make a sample hypeer web
		Connection web = new Connection();
		
		Node testNode1 = web.addNode("first");
		//#0
		Assert.assertEquals(NodeType.LAST_NODE, testNode1.getNodeType());
		NodeState test = testNode1.getNodeState();
		Assert.assertEquals(NodeType.LAST_NODE, test.getType());
		Assert.assertFalse(test.hasEdgeChild(testNode1));
		Assert.assertFalse(test.hasParent(testNode1));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode1));
		test.assertNodeStateIsCorrect(testNode1);
		
		
		Node testNode2 = web.addNode("second");
		//#0
		Assert.assertEquals(NodeType.INTERIOR_NODE, testNode1.getNodeType());
		test = testNode1.getNodeState();
		Assert.assertEquals(test.getType(), testNode1.getNodeType());
		Assert.assertFalse(test.hasEdgeChild(testNode1));
		Assert.assertFalse(test.hasParent(testNode1));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode1));
		test.assertNodeStateIsCorrect(testNode1);
		//#1
		Assert.assertEquals(NodeType.LAST_NODE, testNode2.getNodeType());
		test = testNode2.getNodeState();
		Assert.assertEquals(test.getType(), testNode2.getNodeType());
		Assert.assertFalse(test.hasEdgeChild(testNode2));
		Assert.assertFalse(test.hasParent(testNode2));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode2));
		test.assertNodeStateIsCorrect(testNode2);
		
		
		Node testNode3 = web.addNode("third");
		//#0
		Assert.assertEquals(NodeType.INTERIOR_NODE, testNode1.getNodeType());
		test = testNode1.getNodeState();
		Assert.assertEquals(NodeType.INTERIOR_NODE, test.getType());
		Assert.assertTrue(test.hasEdgeChild(testNode1));
		Assert.assertFalse(test.hasParent(testNode1));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode1));
		test.assertNodeStateIsCorrect(testNode1);
		//#1
		Assert.assertEquals(NodeType.SURFACE_NODE, testNode2.getNodeType());
		test = testNode2.getNodeState();
		Assert.assertEquals(NodeType.SURFACE_NODE, test.getType());
		Assert.assertFalse(test.hasEdgeChild(testNode2));
		Assert.assertTrue(test.hasParent(testNode2));
		Assert.assertEquals(2, test.getFirstUpDownNodeAddress(testNode2).hashCode());
		Assert.assertEquals(2, test.getFirstUpDownNodeAddress(testNode2).getAddress());
		test.assertNodeStateIsCorrect(testNode2);
		//#2
		Assert.assertEquals(NodeType.EDGE_NODE, testNode3.getNodeType());
		test = testNode3.getNodeState();
		Assert.assertEquals(NodeType.EDGE_NODE, test.getType());
		Assert.assertFalse(test.hasEdgeChild(testNode3));
		Assert.assertTrue(test.hasParent(testNode3));
		Assert.assertEquals(1, test.getFirstUpDownNodeAddress(testNode3).hashCode());
		Assert.assertEquals(1, test.getFirstUpDownNodeAddress(testNode3).getAddress());
		test.assertNodeStateIsCorrect(testNode3);
		
		
		Node testNode4 = web.addNode("fourth");
		//#0
		Assert.assertEquals(NodeType.INTERIOR_NODE, testNode1.getNodeType());
		test = testNode1.getNodeState();
		Assert.assertEquals(test.getType(), testNode1.getNodeType());
		Assert.assertFalse(test.hasEdgeChild(testNode1));
		Assert.assertFalse(test.hasParent(testNode1));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode1));
		test.assertNodeStateIsCorrect(testNode1);
		//#1
		Assert.assertEquals(NodeType.INTERIOR_NODE, testNode2.getNodeType());
		test = testNode2.getNodeState();
		Assert.assertEquals(test.getType(), testNode2.getNodeType());
		Assert.assertFalse(test.hasEdgeChild(testNode2));
		Assert.assertTrue(test.hasParent(testNode2));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode2));
		test.assertNodeStateIsCorrect(testNode2);
		//#2
		Assert.assertEquals(NodeType.INTERIOR_NODE, testNode3.getNodeType());
		test = testNode3.getNodeState();
		Assert.assertEquals(test.getType(), testNode3.getNodeType());
		Assert.assertFalse(test.hasEdgeChild(testNode3));
		Assert.assertTrue(test.hasParent(testNode3));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode3));
		test.assertNodeStateIsCorrect(testNode3);
		//#3
		Assert.assertEquals(NodeType.LAST_NODE, testNode4.getNodeType());
		test = testNode4.getNodeState();
		Assert.assertEquals(test.getType(), testNode4.getNodeType());
		Assert.assertFalse(test.hasEdgeChild(testNode4));
		Assert.assertFalse(test.hasParent(testNode4));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode4));
		test.assertNodeStateIsCorrect(testNode4);
		
		Node testNode5 = web.addNode("fifth");
		//#0
		Assert.assertEquals(NodeType.INTERIOR_NODE, testNode1.getNodeType());
		test = testNode1.getNodeState();
		Assert.assertTrue(test.hasEdgeChild(testNode1));
		Assert.assertFalse(test.hasParent(testNode1));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode1));
		test.assertNodeStateIsCorrect(testNode1);
		//#1
		Assert.assertEquals(NodeType.SURFACE_NODE, testNode2.getNodeType());
		test = testNode2.getNodeState();
		Assert.assertFalse(test.hasEdgeChild(testNode2));
		Assert.assertTrue(test.hasParent(testNode2));
		Assert.assertEquals(4, test.getFirstUpDownNodeAddress(testNode2).hashCode());
		test.assertNodeStateIsCorrect(testNode2);
		//#2
		Assert.assertEquals(NodeType.SURFACE_NODE, testNode3.getNodeType());
		test = testNode3.getNodeState();
		Assert.assertFalse(test.hasEdgeChild(testNode3));
		Assert.assertTrue(test.hasParent(testNode3));
		Assert.assertEquals(4, test.getFirstUpDownNodeAddress(testNode3).hashCode());
		test.assertNodeStateIsCorrect(testNode3);
		//#3
		Assert.assertEquals(NodeType.INTERIOR_NODE, testNode4.getNodeType());
		test = testNode4.getNodeState();
		Assert.assertFalse(test.hasEdgeChild(testNode4));
		Assert.assertTrue(test.hasParent(testNode4));
		Assert.assertNull(test.getFirstUpDownNodeAddress(testNode4));
		test.assertNodeStateIsCorrect(testNode4);
		//#4
		Assert.assertEquals(NodeType.EDGE_NODE, testNode5.getNodeType());
		test = testNode5.getNodeState();
		Assert.assertFalse(test.hasEdgeChild(testNode5));
		Assert.assertTrue(test.hasParent(testNode5));
		Assert.assertEquals(1, test.getFirstUpDownNodeAddress(testNode5).hashCode());
		test.assertNodeStateIsCorrect(testNode5);
	}
}
